#include "EventLoop.hpp"
#include "Acceptor.hpp"
#include "TcpConnection.hpp"

#include <func.h>

#include <iostream>

using std::cout;
using std::endl;


#define ARR_MAX_EVENT_SIZE 1024

namespace wd
{

EventLoop::EventLoop(Acceptor & acceptor)
: _epfd(createEpollFd())
, _acceptor(acceptor)
, _isLooping(false)
, _evtArr(ARR_MAX_EVENT_SIZE)
{
    addEpollReadEvent(_acceptor.fd());
}

//loop函数和unloop要运行在不同的线程
void EventLoop::loop()
{
    _isLooping = true;
    while(_isLooping) {
        waitEpollFd();
    }
}

void EventLoop::unloop()
{
    _isLooping = false;
}

void EventLoop::waitEpollFd()
{
    int nready = epoll_wait(_epfd, _evtArr.data(), _evtArr.size(), 5000);
    if(nready == -1 && errno == EINTR) {
        return;
    } else if(nready == -1) {
        perror("epoll_wait");
        return;
    } else if(nready == 0) {
        printf("epoll timeout\n");
        return;
    } else {
        //nready > 0

        for(int i = 0; i < nready; ++i) {
            int fd = _evtArr[i].data.fd;
            if(fd == _acceptor.fd()) {
                //处理新连接
                handleNewConnection();
            } else {
                //已经建立好的连接的处理
                handleMessage(fd);
            }
        }
    }
}

void EventLoop::handleNewConnection()
{
    int peerfd = _acceptor.accept();
    //将peerfd加入到epoll的监听红黑树上
    addEpollReadEvent(peerfd);
    //创建TcpConnection对象
    TcpConnectionPtr conn(new TcpConnection(peerfd));
    //初始化TCP连接的三个函数对象
    conn->setAllCallbacks(_onConnection, 
                          _onMessage, 
                          _onClose);

    //添加到容器中
    _conns.insert(std::make_pair(peerfd, conn));

    //调用连接建立好时的函数对象
    conn->handleNewConnectionCallback();
}

void EventLoop::handleMessage(int peerfd)
{
    //已经建立好的连接的处理
    auto iter = _conns.find(peerfd);
    if(iter != _conns.end()) {
        //map中存放的元素是pair, int -> TcpConnectionPtr
        //判断该连接是否断开了
        bool isClosed = iter->second->isClosed();
        if(isClosed) {
            //连接断开了
            //从epoll的监听红黑树上删除掉
            delEpollReadEvent(peerfd);
            //调用连接断开时的函数对象
            iter->second->handleCloseCallback();
            //从容器_conns中删除掉
            _conns.erase(peerfd);
        } else {
            //消息到达时的处理, 此时还没有读取数据
            iter->second->handleMessageCallback();
        }
    }
}


int EventLoop::createEpollFd()
{
    int fd = epoll_create1(0);
    if(fd < 0) {
        perror("epoll_create1");
    }
    return fd;
}

void EventLoop::addEpollReadEvent(int fd)
{
    struct epoll_event ev;
    memset(&ev, 0, sizeof(ev));
    ev.data.fd = fd;
    ev.events = EPOLLIN;
    int ret = epoll_ctl(_epfd, EPOLL_CTL_ADD, fd, &ev);
    if(ret < 0) {
        perror("epoll_ctl");
    }
}

void EventLoop::delEpollReadEvent(int fd)
{
    struct epoll_event ev;
    memset(&ev, 0, sizeof(ev));
    ev.data.fd = fd;
    int ret = epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, &ev);
    if(ret < 0) {
        perror("epoll_ctl");
    }
}

}//end of namespace wd
